package com.link2room.soundwave.facade.impl;

import com.link2room.common.constant.DefaultValue;
import com.link2room.common.dto.param.base.BaseL2rParamDto;
import com.link2room.common.jpa.result.QueryResult;
import com.link2room.common.service.ICommonService;
import com.link2room.common.util.BatchUtil;
import com.link2room.common.util.DateUtil;
import com.link2room.common.util.TryExceptionUtil;

import com.link2room.enums.exception.SoundwaveSysExceptionEnum;
import com.link2room.optimus.dto.param.base.PriceStaticBaseParamDto;
import com.link2room.optimus.dto.result.base.PriceBaseDto;
import com.link2room.optimus.dto.result.base.PriceDto;
import com.link2room.optimus.dto.result.base.PriceStaticDayDto;
import com.link2room.soundwave.constant.SoundwaveMnsConstant;
import com.link2room.soundwave.constant.SoundwaveTaskNameConstant;
import com.link2room.soundwave.dto.param.base.PmsRateParamDto;
import com.link2room.soundwave.entity.L2RYhHotel;
import com.link2room.soundwave.entity.L2RYhRmtype;
import com.link2room.soundwave.exception.SoundwaveException;
import com.link2room.soundwave.feign.optimus.PriceBaseFeignService;
import com.link2room.soundwave.feign.optimus.StaticPriceFeignService;
import com.link2room.soundwave.service.IYhPmsBaseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import yuheng.pms.result.YhModifyDataDto;
import yuheng.pms.result.YhRmtypePriceDto;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Created by VegetaKo on 2016/11/15.
 */
@Component("yhPmsRateHandlerFacadeService")
public class YhPmsRateHandlerFacadeServiceImpl extends AbstractPmsRateHandlerFacadeServiceImpl{

    @Resource
    private ICommonService commonService;
    @Autowired
    private PriceBaseFeignService priceBaseFeignService;
    @Autowired
    private StaticPriceFeignService staticPriceFeignService;
    @Resource
    private IYhPmsBaseService yhPmsBaseService;


    @Override
    public void syncPMSRate(PmsRateParamDto pmsRateParamDto) throws Exception {
        String lhotelGroupCode=pmsRateParamDto.getLhotelGroupCode();
        L2RYhHotel queryLH=new L2RYhHotel();
        queryLH.setLhotelGroupCode(lhotelGroupCode);
        queryLH.setIsHalt(DefaultValue.F);
        QueryResult<L2RYhHotel> yhHotelResult = commonService.findAllEQ(L2RYhHotel.class, queryLH);
        List<PmsRateParamDto> pmsRateParamDtos=yhHotelResult.getResultlist().stream().map(event->{
            PmsRateParamDto pmsRateParamDto1 = new PmsRateParamDto();
            pmsRateParamDto1.setLhotelGroupCode(lhotelGroupCode);
            pmsRateParamDto1.setLhotelCode(event.getLhotelCode());
            pmsRateParamDto1.setPmsGroupCode(event.getGroupCode());
            pmsRateParamDto1.setPmsHotelCode(event.getHotelCode());
            pmsRateParamDto1.setStartDate(pmsRateParamDto.getStartDate());
            pmsRateParamDto1.setEndDate(pmsRateParamDto.getEndDate());
            return pmsRateParamDto1;
        }).filter(obj->obj!=null).collect(Collectors.toList());
        BatchUtil.beginBatchTaskInterval(SoundwaveMnsConstant.QUEUE_PMSRATE,
                SoundwaveTaskNameConstant.SAVE_PMS_RATE,
                pmsRateParamDtos,10);
    }

    private List<PriceStaticDayDto> doPrice(String lhotelGroupCode ,
                                            String lhotelCode,
                                            String pmsGroupCode,
                                            String pmsHotelCode,
                                            String priceCode,
                                            String startDate,
                                            String endDate,
                                            PriceDto priceDto) throws Exception {
        //获取PMS对应房型价格
        L2RYhRmtype  queryLR = new L2RYhRmtype();
        queryLR.setLhotelGroupCode(lhotelGroupCode );
        queryLR.setLhotelCode(lhotelCode );
        queryLR.setL2RRmtype(priceDto.getRmtype() );
        L2RYhRmtype l2RYhRmtype = commonService.findOnlyOneEQ(L2RYhRmtype.class, queryLR);
        return Optional.ofNullable(l2RYhRmtype).map(TryExceptionUtil.of(yhRmtype->{
                List<YhRmtypePriceDto> yhRoomPriceList = yhPmsBaseService.getYhRoomPriceList(lhotelGroupCode, pmsGroupCode, pmsHotelCode, yhRmtype.getPmsRmtype(), priceCode, startDate, endDate);
                return yhRoomPriceList.stream().map(roomPrice-> {
                    BigDecimal staticPrices =Optional.ofNullable(priceDto.getStaticPrices()).filter(list->list.size()>0).map(list->list.stream().findFirst().get().getPrice()).orElse(null);
                    BigDecimal weekPrices= Optional.ofNullable(priceDto.getWeekPrices()).filter(wPrices -> wPrices.size() > 0).flatMap(wPrices ->
                            Optional.ofNullable(wPrices.stream().filter(wPrice -> {
                                if (Objects.equals(wPrice.getWeekd(), DateUtil.getDateWeek(roomPrice.getBusinessDate())) && Objects.equals(DefaultValue.F, wPrice.getIsHalt())) {
                                    return true;
                                }
                                return false;
                            }).findAny().map(value->value.getPrice()).orElse(null))
                    ).orElse(null);
                boolean flag;
                flag=Optional.ofNullable(staticPrices).filter(value->value.compareTo(new BigDecimal(roomPrice.getActualRate()))!=0).map(value->true).orElse(false);
                if(!flag){
                    flag=Optional.ofNullable(weekPrices).filter(value->value.compareTo(new BigDecimal(roomPrice.getActualRate()))!=0).map(value->true).orElse(false);
                }
                PriceStaticDayDto priceStaticDayDto=null;
                    if(flag){
                        priceStaticDayDto = new PriceStaticDayDto();
                        priceStaticDayDto.setPrice(new BigDecimal(roomPrice.getActualRate()));
                        priceStaticDayDto.setLhotelGroupCode(lhotelGroupCode);
                        priceStaticDayDto.setLhotelCode(lhotelCode);
                        priceStaticDayDto.setPriceCode(priceCode);
                        priceStaticDayDto.setRmtype(priceDto.getRmtype());
                        priceStaticDayDto.setPriceDate(roomPrice.getBusinessDate());
                    }
                    return priceStaticDayDto;
                }).filter(value->value!=null).collect(Collectors.toList());
            })
        ).orElseThrow(()->new SoundwaveException(SoundwaveSysExceptionEnum.YHPMS_MAPPINGRMTYPE_NOT_EXIT));

    }

    private void doSyncRate(String lhotelGroupCode ,
                            String lhotelCode,
                            String pmsGroupCode,
                            String pmpsHotelCode,
                            String startDate,
                            String endDate,
                            PriceBaseDto priceBaseDto) throws Exception {
        PriceStaticBaseParamDto priceStaticParamDto = new PriceStaticBaseParamDto();
        priceStaticParamDto.setLhotelGroupCode(lhotelGroupCode);
        priceStaticParamDto.setLhotelCode(lhotelCode);
        priceStaticParamDto.setPriceCode(priceBaseDto.getPriceCode());
        priceStaticParamDto.setStartDatetime(startDate);
        priceStaticParamDto.setEndDatetime(endDate);
        QueryResult<PriceDto> priceDtoQueryResult = staticPriceFeignService.getStaticPrices(priceStaticParamDto.paramToMap()).getQueryResult();
        List<String> errorRmtypes=Optional.ofNullable(priceDtoQueryResult.getResultlist()).map(list->
          list.stream().map(TryExceptionUtil.of(event->{
                String errorRoomType=null;
                try {
                    List<PriceStaticDayDto> priceStaticDayDtoList = this.doPrice(lhotelGroupCode, lhotelCode,pmsGroupCode,pmpsHotelCode, priceBaseDto.getPriceCode(),  startDate, endDate,event );
                    Optional.ofNullable(priceStaticDayDtoList).filter(priceDayList->priceDayList.size()>0).ifPresent(TryExceptionUtil.of(
                            dayPriceList->{
                                PriceStaticBaseParamDto priceStaticParamDto1 = new PriceStaticBaseParamDto();
                                priceStaticParamDto1.setLhotelGroupCode(lhotelGroupCode);
                                priceStaticParamDto1.setLhotelCode(lhotelCode);
                                priceStaticParamDto1.setPriceCode(priceBaseDto.getPriceCode());
                                priceStaticParamDto1.setStartDatetime(startDate);
                                priceStaticParamDto1.setEndDatetime(endDate);
                                priceStaticParamDto1.setRmtype(event.getRmtype());
                                priceStaticParamDto1.setDayPrices(dayPriceList);
                                staticPriceFeignService.updateStaticPrices(priceStaticParamDto1);
                            }
                    ));
                }catch (SoundwaveException e){
                    if(e.getCode()==SoundwaveSysExceptionEnum.YHPMS_MAPPINGRMTYPE_NOT_EXIT.getCode()){
                        errorRoomType=event.getRmtype();
                    }
                }
                return errorRoomType;
            }
            )).filter(error->error!=null).collect(Collectors.toList())
        ).orElse(Collections.emptyList());
        Optional.ofNullable(errorRmtypes).filter(list->list.size()>0).ifPresent((list)->{
            throw new SoundwaveException(SoundwaveSysExceptionEnum.YHPMS_MAPPINGRMTYPE_NOT_EXIT,"缺失映射房型："+list.stream().filter(value->value!=null).collect(Collectors.joining(",")));
        });
    }

    @Override
    public void syncPMSHotelRate(PmsRateParamDto pmsRateParamDto) throws Exception {
        BaseL2rParamDto baseL2rParamDto =new BaseL2rParamDto();
        QueryResult<PriceBaseDto> priceBaseDtoQueryResult = priceBaseFeignService.getPriceBases(baseL2rParamDto.paramToMap()).getQueryResult();
        Optional.ofNullable(priceBaseDtoQueryResult.getResultlist()).ifPresent(priceBaseList->priceBaseList.stream().forEach(
               TryExceptionUtil.of(pbd->{
                   this.doSyncRate(pmsRateParamDto.getLhotelGroupCode(),
                                   pmsRateParamDto.getLhotelCode(),
                                   pmsRateParamDto.getPmsGroupCode(),
                                   pmsRateParamDto.getPmsHotelCode(),
                                   pmsRateParamDto.getStartDatetime(),
                                   pmsRateParamDto.getEndDatetime(),
                                   pbd
                                   );
                    }
               )
        ));
        BatchUtil.doBatchTaskDone(pmsRateParamDto.getTaskMainId(), pmsRateParamDto.getTaskId(), pmsRateParamDto.getIsBatch());
    }

    @Override
    void syncPMSRateIncrement(PmsRateParamDto pmsRateParamDto) throws Exception {
        String lhotelGroupCode=pmsRateParamDto.getLhotelGroupCode();
        String lastModifyDate=pmsRateParamDto.getLastModifyDate();
        L2RYhHotel queryLH=new L2RYhHotel();
        queryLH.setLhotelGroupCode(lhotelGroupCode);
        queryLH.setLhotelCode(pmsRateParamDto.getLhotelCode());
        queryLH.setIsHalt(DefaultValue.F);
        QueryResult<L2RYhHotel> yhHotelResult = commonService.findAllEQ(L2RYhHotel.class, queryLH);
        L2RYhHotel l2RYhHotel=Optional.ofNullable(yhHotelResult.getResultlist()).map(list->list.stream().findAny().get()).orElseThrow(()->new SoundwaveException(SoundwaveSysExceptionEnum.YHPMS_MAPPINGHOTEL_NOT_EXIT));
        Map<String, List<YhModifyDataDto>> modifyMap = yhPmsBaseService.getModifyData(lhotelGroupCode, l2RYhHotel.getGroupCode(), null, pmsRateParamDto.getLastModifyDate() );
        List<PmsRateParamDto> pmsRateParamDtos=yhHotelResult.getResultlist().stream().map(event->{
            List<YhModifyDataDto> yhModifyDataDtos=modifyMap.get(event.getHotelCode());
            return Optional.ofNullable(yhModifyDataDtos).map(
                    list->{
                        PmsRateParamDto pmsRateParamDto1 = new PmsRateParamDto();
                        pmsRateParamDto1.setLhotelGroupCode(lhotelGroupCode);
                        pmsRateParamDto1.setLhotelCode(event.getLhotelCode());
                        pmsRateParamDto1.setPmsGroupCode(event.getGroupCode());
                        pmsRateParamDto1.setPmsHotelCode(event.getHotelCode());
                        pmsRateParamDto1.setLastModifyDate(lastModifyDate);
                        pmsRateParamDto1.setYhRateRmtypeMap(list.stream().collect(Collectors.groupingBy(value->value.getRateCode())));
                        return pmsRateParamDto1;
                    }
            ).orElse(null);
        }).filter(obj->obj!=null).collect(Collectors.toList());
        BatchUtil.beginBatchTask(SoundwaveMnsConstant.QUEUE_PMSRATE_INCREMENT,
                SoundwaveTaskNameConstant.SAVE_PMS_RATE_INCREMENT,
                pmsRateParamDtos);
    }

    @Override
    void syncPMSRateHotelIncrement(PmsRateParamDto pmsRateParamDto) throws Exception {
        BaseL2rParamDto baseL2rParamDto =new BaseL2rParamDto();
        QueryResult<PriceBaseDto> priceBaseDtoQueryResult = priceBaseFeignService.getPriceBases(baseL2rParamDto.paramToMap()).getQueryResult();
        Optional.ofNullable(priceBaseDtoQueryResult.getResultlist()).ifPresent(priceBaseList->priceBaseList.stream().forEach(
                TryExceptionUtil.of(pbd->{
                        if(pmsRateParamDto.getYhRateRmtypeMap().get(pbd.getPriceCode())!=null){
                            List<YhModifyDataDto> list=new ArrayList<>();
                            List<YhModifyDataDto> yhmodifyDataList=pmsRateParamDto.getYhRateRmtypeMap().get("Base");
                            List<YhModifyDataDto> yhmodifyDataList1=pmsRateParamDto.getYhRateRmtypeMap().get(pbd.getPriceCode());
                            if(yhmodifyDataList!=null){
                                list.addAll(yhmodifyDataList);
                            }
                            if(yhmodifyDataList1!=null){
                                list.addAll(yhmodifyDataList1);
                            }
                            this.doSyncRateIncrement(pmsRateParamDto.getLhotelGroupCode(),
                                    pmsRateParamDto.getLhotelCode(),
                                    pmsRateParamDto.getPmsGroupCode(),
                                    pmsRateParamDto.getPmsHotelCode(),
                                    pbd.getPriceCode(),
                                    list
                            );
                        }
                    }
                )
        ));
        BatchUtil.doBatchTaskDone(pmsRateParamDto.getTaskMainId(), pmsRateParamDto.getTaskId(), pmsRateParamDto.getIsBatch());
    }

    private void doSyncRateIncrement(String lhotelGroupCode ,
                                     String lhotelCode,
                                     String pmsGroupCode,
                                     String pmsHotelCode,
                                     String priceCode,
                                     List<YhModifyDataDto> yhModifyDataDtoList) throws Exception {
        L2RYhRmtype queryYhRmtype=new L2RYhRmtype();
        queryYhRmtype.setLhotelGroupCode(lhotelGroupCode);
        queryYhRmtype.setLhotelCode(lhotelCode);
        queryYhRmtype.setIsHalt(DefaultValue.F);
        QueryResult<L2RYhRmtype> l2RYhRmtypeQueryResult = commonService.findAllEQ(L2RYhRmtype.class, queryYhRmtype);
        Optional.ofNullable(l2RYhRmtypeQueryResult.getResultlist()).ifPresent(list->{
            list.stream().forEach(
                    l2RYhRmtype->
                        yhModifyDataDtoList.stream().filter(
                                modifyData -> Objects.equals(modifyData.getRoomType(), l2RYhRmtype.getPmsRmtype())
                        ).forEach(TryExceptionUtil.of(
                                modifyData -> {
                                    List<YhRmtypePriceDto> yhRmtypePriceDtos=  yhPmsBaseService.getYhRoomPriceList(
                                            lhotelGroupCode,
                                            pmsGroupCode,
                                            pmsHotelCode,
                                            modifyData.getRoomType(),
                                            priceCode,
                                            DateUtil.getNewFormatDateString(modifyData.getStartDate()),
                                            DateUtil.getNewFormatDateString(modifyData.getEndDate())
                                    );
                                    List<PriceStaticDayDto> priceStaticDayDtoList=yhRmtypePriceDtos.stream().map(yhRmtypePriceDto -> {
                                        PriceStaticDayDto priceStaticDayDto = new PriceStaticDayDto();
                                        priceStaticDayDto.setPrice(new BigDecimal(yhRmtypePriceDto.getActualRate()));
                                        priceStaticDayDto.setLhotelGroupCode(lhotelGroupCode);
                                        priceStaticDayDto.setLhotelCode(lhotelCode);
                                        priceStaticDayDto.setPriceCode(priceCode);
                                        priceStaticDayDto.setRmtype(l2RYhRmtype.getL2RRmtype());
                                        priceStaticDayDto.setPriceDate(yhRmtypePriceDto.getBusinessDate());
                                        return priceStaticDayDto;
                                    }).collect(Collectors.toList());
                                    PriceStaticBaseParamDto priceStaticParamDto = new PriceStaticBaseParamDto();
                                    priceStaticParamDto.setLhotelGroupCode(lhotelGroupCode);
                                    priceStaticParamDto.setLhotelCode(lhotelCode);
                                    priceStaticParamDto.setPriceCode(priceCode);
                                    priceStaticParamDto.setStartDatetime(DateUtil.getNewFormatDateString(modifyData.getStartDate()));
                                    priceStaticParamDto.setEndDatetime(DateUtil.getNewFormatDateString(modifyData.getEndDate()));
                                    priceStaticParamDto.setRmtype(l2RYhRmtype.getL2RRmtype());
                                    priceStaticParamDto.setDayPrices(priceStaticDayDtoList);
                                    staticPriceFeignService.updateStaticPricesIncrement(priceStaticParamDto);
                                }
                        ))
                    );
                }
            );
    }
}
